Nacteni textoveho souboru do string promenne
Otázka od: Martin Radvansky
14. 7. 2004 13:00
Dobry den,
Narazil jsem na problem s dobu nacitani textoveho souboru
Zde je ukazka kodu
while not EOF(ltfFile) do begin
Readln(ltfFile, lsRow);
.
.
.
lsText := lsText + lsRow + #13;
end;
Pokud nacitam textovy soubor timto zpusobem, soubor ma asi 3,5MB
asi 33500 radku, tak doba, kterou na to potrebuje 3.2G P4 HT je
kolem 120 sec (coz je katastroficke). Podle profileru je to zpusobeno tim
prirazovanim
lsText := lsText + lsRow;
pokud si testuju pouze lsText := lsRow + #13;
tak je rychlost nekde na urovni setin sekundy.
Existuje neco jako prirazeni "pripojenim" k retezci?
Diky za radu.
--
S pozdravem,
Martin Radvansky
Odpovedá: Fitz Ladislav
14. 7. 2004 14:30
ja si na to udelal object, neni to nic svetoborneho ale me to staci
pred nacitanim zavolas StartSet; a po nacitani EndSet ktery ti vrati nacteny
string
snad to pomuze
tLongString = class
private
FString : string;
FLength,
FSize,
FPosition : longint;
procedure _Free;
public
constructor Create;
destructor Destroy; override;
property Length : longint read FLength;
function StartTransaction : longint;
procedure CancelTransaction (value : longint);
procedure StartSet;
function EndSet : string;
procedure AddChar (ch : char);
procedure AddLine;
procedure AddText (const txt : string);
end;
procedure tLongString._Free;
begin
FString:='';
FLength:=0;
FSize:=0;
FPosition:=0;
end;
constructor tLongString.Create;
begin
inherited Create;
_Free;
end;
destructor tLongString.Destroy;
begin
_Free;
inherited;
end;
function tLongString.StartTransaction : longint;
begin
result:=FPosition;
end;
procedure tLongString.CancelTransaction (value : longint);
begin
FPosition:=value;
FLength:=value-1;
end;
procedure tLongString.StartSet;
begin
FLength:=0;
FSize:=$4000;
FPosition:=1;
SetLength (FString,FSize);
end;
function tLongString.EndSet : string;
begin
result:=Copy (FString,1,FLength);
_Free;
end;
procedure tLongString.AddChar (ch : char);
begin
if (FPosition>=FSize) then
begin
inc (FSize,$4000);
SetLength (FString,FSize);
end;
FString[FPosition]:=ch;
inc (FPosition);
inc (FLength);
end;
procedure tLongString.AddLine;
begin
if (FPosition+1>=FSize) then
begin
inc (FSize,$4000);
SetLength (FString,FSize);
end;
FString[FPosition]:=#13;
inc (FPosition);
FString[FPosition]:=#10;
inc (FPosition);
inc (FLength,2);
end;
procedure tLongString.AddText (const txt : string);
var l : longint;
begin
l:=system.Length (txt);
if (l>0) then
begin
if (FPosition+l>=FSize) then
begin
inc (FSize,$4000*(1+(l div $4000)));
SetLength (FString,FSize);
end;
Move (txt[1],FString[FPosition],l);
inc (FPosition,l);
inc (FLength,l);
end;
end;
Odpovedá: Daniel Frantik
14. 7. 2004 14:33
> -----Original Message-----
> Dobry den,
> Narazil jsem na problem s dobu nacitani textoveho souboru
> Zde je ukazka kodu
> while not EOF(ltfFile) do begin
> Readln(ltfFile, lsRow);
> lsText := lsText + lsRow + #13;
> end;
Ahoj,
problem je v realokaci pameti pro ulozeni stringu lsText pri kazdem
prirazeni.
Reseni co me napadaji na prvni pohled:
a) TStringList.LoadFromFile - 3,5MB by nemel byt problem ... nicmene
sekundy to asi budou
b) Pouzit streamy
c) alokovat pevny kus pameti a pak presunovat data
Danik
Odpovedá: Milan Tomes
14. 7. 2004 13:57
A proc s tim nepracujes jako se streamem ??? Jeste lepsi je
MemoryMappedFile. Podivej se do unity JclFileUtils na tridu
TJclMappedTextReader. Myslim, ze Ti hodne pomuze a hlavne cely proces
neskutecne zrychli. Pokud potrebujes nacist cely soubor do jednoho stringu,
tak se podivej na unitu JclStrings a funkci FileToString.
HTH
S pozdravem
Milan Tomes
> [mailto:delphi-l-owner@clexpert.cz]On Behalf Of Martin Radvansky
> Sent: Wednesday, July 14, 2004 1:22 PM
>
> Dobry den,
> Narazil jsem na problem s dobu nacitani textoveho souboru
> asi 33500 radku, tak doba, kterou na to potrebuje 3.2G P4 HT je
> kolem 120 sec (coz je katastroficke). Podle profileru je to
> Martin Radvansky
Odpovedá: Vaclav Sazima
14. 7. 2004 13:43
Ahoj,
1. Zkusil bych jak dopadne TStringList.loadfromfile
nebo
S : TFileStream;
lsText : string;
...
setlength (lsText,S.Size);
S.ReadBuffer (isText [1],S.Size);
...
Martin Radvansky wrote:
> Narazil jsem na problem s dobu nacitani textoveho souboru
Odpovedá: Pavel Poles
14. 7. 2004 14:03
> Zde je ukazka kodu
> while not EOF(ltfFile) do begin
> Readln(ltfFile, lsRow);
> .
> .
> .
> lsText := lsText + lsRow + #13;
> end;
A co pomoci Tstringlist.LoadFromFile? Myslim ze by to melo byt rychlejsi,
a jako string to pak dostane pre TStringList.Text, nebo
TStringList.DelimitedText
to se prevadi pres Pchar takze je to rychle.
> Pokud nacitam textovy soubor timto zpusobem, soubor ma asi 3,5MB
> asi 33500 radku, tak doba, kterou na to potrebuje 3.2G P4 HT je
> kolem 120 sec (coz je katastroficke). Podle profileru je to zpusobeno
tim prirazovanim
> lsText := lsText + lsRow;
Scitani stringu strasne zpomaluje. Optimalizace je jedine pracovat s PChar a
ne se stringem.
Pavel Poles
Odpovedá: Petr Vones
14. 7. 2004 14:53
From: "Martin Radvansky" <delphiconf@radvansky.net>
> Existuje neco jako prirazeni "pripojenim" k retezci?
Samozrejme, alokovat retezec o velikosti souboru a do tohoto bufferu nahrat
data primo. Viz funkce FileToString v JCL: http://sourceforge.net/projects/jcl
Petr Vones
Odpovedá: Ludek Finstrle
14. 7. 2004 14:36
> Existuje neco jako prirazeni "pripojenim" k retezci?
Musel bys to udelat pres PChar a pak tam neco jako pripojeni nakonec je.
Ale PChar musis alokovat v pameti (coz by +- podle velikosti souboru
snad nemel byt az tak velky problem).
Luf
Odpovedá: Martin Radvansky
15. 7. 2004 7:03
Dobry den,
PV> Samozrejme, alokovat retezec o velikosti souboru a do tohoto bufferu nahrat
PV> data primo. Viz funkce FileToString v JCL:
PV> http://sourceforge.net/projects/jcl
Diky vsem za pomoc, pouzil jsem jcl FileToString. Rychlot nacteni je
prakticky okamzite.
--
S pozdravem,
Martin Radvansky